package 设计模式;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 代理模式
 *  接口的应用
 * 代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其
 * 他对象提供一种代理以控制对这个对象的访问。
 *
 *
 * ●应用场景:
 *      ➢安全代理:屏蔽对真实角色的直接访问。
 *      ➢远程代理:通过代理类处理远程方法调用(RMI)
 *      ➢延迟加载:先加载轻量级的代理对象，真正需要再加载真实对象
 *          比如你要开发-一个大文档查看软件，大文档中有大的图片，有可能一个图片有
 *          100MB， 在打开文件时，不可能将所有的图片都显示出来，这样就可以使用代理
 *          模式，当需要查看图片时，用proxy来进行大图片的打开。
 * ●分类
 *      ➢静态代理(静态定义代理类)
 *      ➢动态代理(动态生成代理类)
 *       JDK自带的动态代理，需要反射等知识
 */

public class 代理模式 {
    public static void main(String[] args) {
        动态代理();

    }

    private static void 动态代理() {
        Server server = new Server();//被代理类
        NetWork netWork = (NetWork) ProxyFactory.getProxyInstance(server);//代理类
        netWork.browse();
    }

    private static void 静态代理() {
        //静态代理
        Server server = new Server();//被代理类
        ProxyServer proxyServer = new ProxyServer(server);//代理类
        proxyServer.browse();
    }
}
interface NetWork{
    public void browse();
}

class Server implements NetWork{

    @Override
    public void browse() {
        System.out.println("真实的服务器访问网络");
    }
}//被代理类

class ProxyServer implements NetWork{

    private NetWork work;

    public ProxyServer(NetWork work) {
        this.work = work;
    }

    public void check(){
        System.out.println("联网之前的检查工作");
    }
    @Override
    public void browse() {
        check();
        work.browse();
    }
} //代理类

class Utils{
    public void method1(){
        System.out.println("====通用方法01================");
    }
    public void method2(){
        System.out.println("====通用方法02================");
    }
}


class  ProxyFactory{

    public static Object getProxyInstance(Object obj){//被代理类对象
        MyInvocationHandler handler = new MyInvocationHandler();
        handler.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),//取得该Class对象的类装载器
                obj.getClass().getInterfaces()/*获得obj的接口*/,handler);
    }
}

class MyInvocationHandler implements InvocationHandler{
    private Object obj;//需要使用被代理类的对象进行赋值
    public void bind(Object obj){
        this.obj = obj;
    }

    //当我们通过代理类的对象，调用方法a时，就会自动的调用如下的方法：invoke()
    //将被代理类要执行的方法a的功能就声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Utils utils = new Utils();

        utils.method1();
        //method:即为代理类对象调用的方法，此方法也就作为了被代理类对象要调用的方法
        //obj:被代理类的对象
        Object invoke = method.invoke(obj, args);
        //上述方法的返回值就作为当前类中的invoke()的返回值。


        utils.method2();
        return invoke;
    }
}